powerpointproto slides.waow.tech
slides
at main 100 lines 2.6 kB view raw
1const DECK_COLLECTION = "tech.waow.slides.deck"; 2 3async function resolveHandleToDid(handle: string): Promise<string | null> { 4 // strip @ if present 5 const cleanHandle = handle.replace(/^@/, ""); 6 7 try { 8 const res = await fetch( 9 `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(cleanHandle)}` 10 ); 11 if (res.ok) { 12 const data = await res.json(); 13 return data.did || null; 14 } 15 } catch {} 16 return null; 17} 18 19async function resolvePds(did: string): Promise<string> { 20 try { 21 if (did.startsWith("did:plc:")) { 22 const res = await fetch(`https://plc.directory/${did}`); 23 if (res.ok) { 24 const doc = await res.json(); 25 const pds = doc.service?.find( 26 (s: { id: string; serviceEndpoint?: string }) => s.id === "#atproto_pds" 27 ); 28 if (pds?.serviceEndpoint) return pds.serviceEndpoint; 29 } 30 } 31 } catch {} 32 return "https://bsky.social"; 33} 34 35type DeckRecord = { 36 name: string; 37 slides: Array<{ subject: { uri: string; cid: string } }>; 38 createdAt: string; 39 updatedAt?: string; 40 thumbnail?: { 41 ref: { $link: string }; 42 mimeType: string; 43 }; 44}; 45 46async function listDecks(did: string) { 47 const pdsUrl = (await resolvePds(did)).replace(/\/$/, ""); 48 49 try { 50 const res = await fetch( 51 `${pdsUrl}/xrpc/com.atproto.repo.listRecords?repo=${did}&collection=${DECK_COLLECTION}&limit=100` 52 ); 53 if (!res.ok) return []; 54 const data = await res.json(); 55 56 // eslint-disable-next-line @typescript-eslint/no-explicit-any 57 return data.records.map((r: any) => { 58 const val = r.value as DeckRecord; 59 const rkey = r.uri.split("/").pop()!; 60 const thumbnailUrl = val.thumbnail 61 ? `${pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(did)}&cid=${encodeURIComponent(val.thumbnail.ref.$link)}` 62 : null; 63 return { 64 uri: r.uri, 65 rkey, 66 name: val.name, 67 slideCount: val.slides?.length || 0, 68 createdAt: val.createdAt, 69 updatedAt: val.updatedAt, 70 thumbnailUrl, 71 }; 72 }); 73 } catch { 74 return []; 75 } 76} 77 78export const load = async ({ params }) => { 79 const { handle } = params; 80 const cleanHandle = handle.replace(/^@/, ""); 81 82 const did = await resolveHandleToDid(cleanHandle); 83 if (!did) { 84 return { 85 handle: cleanHandle, 86 did: null, 87 decks: [], 88 error: "user not found", 89 }; 90 } 91 92 const decks = await listDecks(did); 93 94 return { 95 handle: cleanHandle, 96 did, 97 decks, 98 error: null, 99 }; 100};